package com.shareyi.netty.nio;

import com.shareyi.netty.log.LogHelper;
import org.apache.commons.collections4.CollectionUtils;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.nio.charset.Charset;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.BlockingDeque;

/**
 * Nio 单线程读取器
 *
 * @author zhangshibin
 * @since 2018/9/9
 */
public class NioSingleThreadReader implements Runnable {

    /**
     * 服务器selector
     */
    Selector serverSelector;

    Handler handler;

    /**
     * 第一次接受到请求才能设置为true
     */
    boolean start;

    public NioSingleThreadReader(Selector serverSelector) {
        this.serverSelector = serverSelector;
        handler = new Handler(1024);
    }

    public void run() {
        try {
            while (true) {
                if(!start){
                    Thread.yield();
                    continue;
                }
                //等待请求，每次等待阻塞3s，超过时间则向下执行，若传入0或不传值，则在接收到请求前一直阻塞
                if (serverSelector.select(200) == 0) {
                    //System.out.println("等待请求超时......");
                    continue;
                }
              //  serverSelector.select();
                Set<SelectionKey> selectionKeySet = serverSelector.selectedKeys();
                if (CollectionUtils.isEmpty(selectionKeySet)) {
                    Thread.sleep(10);
                    // Thread.yield();
                }
                LogHelper.DEFAULT.info("一共有selectKey={}", selectionKeySet.size());

                Iterator<SelectionKey> iterator = selectionKeySet.iterator();
                while (iterator.hasNext()) {
                    handler.handleRead(iterator.next());
                    iterator.remove();
                }
            }
        } catch (Exception e) {
            LogHelper.EXCEPTION.error("处理出现异常", e);
        }

    }

    public Selector getServerSelector() {
        return serverSelector;
    }

    public void setServerSelector(Selector serverSelector) {
        this.serverSelector = serverSelector;
    }

    public boolean isStart() {
        return start;
    }

    public void setStart(boolean start) {
        this.start = start;
    }

    public void registerChannel(SocketChannel socketChannel) throws IOException {
        socketChannel.configureBlocking(false);
        socketChannel.register(serverSelector, SelectionKey.OP_READ, ByteBuffer.allocate(1024));
        this.start = true;
    }

    /*
        处理器类
    */
    private static class Handler{
        private int bufferSize = 1024; //缓冲器容量
        private String localCharset = "UTF-8"; //编码格式

        public Handler(){}
        public Handler(int bufferSize){
            this(bufferSize,null);
        }
        public Handler(String localCharset){
            this(-1,localCharset);
        }
        public Handler(int bufferSize,String localCharset){
            if(bufferSize > 0){
                this.bufferSize = bufferSize;
            }
            if(localCharset != null){
                this.localCharset = localCharset;
            }
        }


        public void handleRead(SelectionKey selectionKey) throws IOException {
            //获取套接字通道
            SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
            //获取缓冲器并进行重置,selectionKey.attachment()为获取选择器键的附加对象
            ByteBuffer byteBuffer = (ByteBuffer)selectionKey.attachment();
            byteBuffer.clear();
            //没有内容则关闭通道
            if (socketChannel.read(byteBuffer) == -1) {
                socketChannel.close();
            } else {
                //将缓冲器转换为读状态
                byteBuffer.flip();
                //将缓冲器中接收到的值按localCharset格式编码保存
                String receivedRequestData = Charset.forName(localCharset).newDecoder().decode(byteBuffer).toString();
                System.out.println("接收到客户端的请求数据："+receivedRequestData);
                //返回响应数据给客户端
                String responseData = "receive your data,response is: "+ receivedRequestData;
                byteBuffer = ByteBuffer.wrap(responseData.getBytes(localCharset));
                socketChannel.write(byteBuffer);
                //关闭通道
                socketChannel.close();
            }
        }
    }

}
